#-------------------------------------------------------------------------------
# Name:        CropDetcShortCircuit
# Purpose:
#
# Author:      Daiyusi
#
# Created:     23/07/2021
# Copyright:   (c) asus 2021
# Licence:     <your licence>
#-------------------------------------------------------------------------------

import numpy as np
import os
from PIL import Image,ImageFont,ImageDraw
import matplotlib.pyplot as plt

class CropDetc2:
    def avg_sum(self, im):
        # 面均值
        s = np.float(0)
        h, w = im.shape
        for i in range(h):
            for j in range(w):
                s = s * ((i * w + j) / (i * w + j + 1)) + im[i, j] / (i * w + j + 1)
        return s

    def max_avg_sum(self, im):
        # 线均值最大值
        h, w = im.shape
        maxs = 0
        for i in range(w):
            s = np.float(0)
            for j in range(h):
                s = s * (j / (j + 1)) + im[j, i] / (j + 1)
            if s > maxs:
                maxs = s
        return maxs

    def max2_avg_sum(self, im):
        # 半线均值最大值
        h, w = im.shape
        h2 = int(h / 2)
        maxs1 = self.max_avg_sum(im[0:h2, 0:])
        maxs2 = self.max_avg_sum(im[h2:, 0:])

        if maxs1 > maxs2:
            return maxs1
        else:
            return maxs2
        '''
        s = (maxs1+maxs2)/2
        return s
        '''

    def max3_avg_sum(self, im):
        # (半)线均值最大值与面均值的加权平均
        s = np.float(0)
        s0 = self.avg_sum(im)
        s1 = self.max_avg_sum(im)
        s2 = self.max2_avg_sum(im)
        s = 0.7 * s2 + 0.3 * s0
        return s

    def uncovSearch(self, avgT, meanT):
        # 头尾板搜索计数,以p倍meanT为界
        n = [1, 1]  # [头,尾]
        p = 1.20

        for i in avgT[1:]:
            if i > p * meanT:
                n[0] = n[0] + 1
            else:
                if n[0] == 1 and avgT[0] < p * meanT:
                    n[0] = 0
                break

        for i in avgT[-2::-1]:
            if i > p * meanT:
                n[1] = n[1] + 1
            else:
                if n[1] == 1 and avgT[-1] < p * meanT:
                    n[1] = 0
                break

        print('n:', n)
        return n

    def T2P(self, T, minT, maxT):
        # P = (T-minT)*255/(maxT-minT)
        k = 255 / (maxT - minT)
        P = []

        if type(T) is list:
            for i in T:
                p0 = (i - minT) * k
                P.append(p0)
        else:
            P = (T - minT) * k

        return P

    def thDynamic(self, th0, minT, maxT):
        th=[]
        for i in th0:
            th.append(i)
        return th


    def stdDetect(self, im, minT, maxT):
        # 单槽板极短路检测
        levelSC = self.levelSC
        num = self.num3

        diag = [0 for i in range(num)]
        avgT = [0 for i in range(num)]
        h, w = im.shape
        stp = w / num

        # 极板特征值列表求取
        for i in range(num):
            p1 = int(i * stp)
            p2 = int((i + 1) * stp)
            subim = im[0:, p1:p2]
            avgT[i] = self.max3_avg_sum(subim)
            # print('avgT[', str(i + 1), ']:', avgT[i])

        ## List Of avgT
        self.ListExtr_avg.append(avgT)

        meanT = np.mean(avgT)  # 均值
        stdT = np.std(avgT)  # 标准差
        #    print('meanT1:',meanT)

        difT = avgT - meanT
        uncov = [1 for i in range(num)]  # 有多层盖布处标记0
        num_uncov = num
        sum_uncov = 0
        thuncov = -20
        for i in range(num):
            if difT[i] < thuncov:
                num_uncov = num_uncov - 1
                uncov[i] = 0
            sum_uncov = sum_uncov + uncov[i] * avgT[i]

        meanT = sum_uncov / num_uncov
        # print('meanT:', meanT)

        # 前后端n个板极忽略，不纳入均值计算

        #T1 = 66.5  # 盖布与不盖布的均温划分界限
        #P1 = self.T2P(T1, minT, maxT)
        P1 = 180
        n = [0, 0]
        print('meanT1:',meanT)
        if meanT < P1:
            n = self.uncovSearch(avgT, meanT)
            for i in range(-n[1], n[0]):
                #n.append(avgT[i])
                if uncov[i] == 1:
                    # uncov[i] = 0
                    num_uncov = num_uncov - 1
                    sum_uncov = sum_uncov - avgT[i]
            meanT = sum_uncov / num_uncov

        self.ListExtr_ns.append(n) # List Of n
        difT = avgT - meanT

        # 忽略前后n个板极，以及多层盖布后求标准差
        avgT_normal = []
        for i in range(n[0], num - n[1]):
            if uncov[i] == 1:
                avgT_normal.append(avgT[i])
        stdT = np.std(avgT_normal)

        print('meanT2:', meanT)
        print('stdT:', stdT)
        print('avgT:', avgT)
        # print('difT:', difT)

        '''
        k3, k2, k1 = [4, 2, 1.7]

        # # 标准差过小
        thrSTD = 0.1
        if stdT < thrSTD * meanT:
            k3, k2, k1 = [5, 3, 2]
        '''

        thrSTD = [0.1, 0.05]
        thAVG = [160,180,200]
        k3, k2, k1 = [3.5, 2.5, 2.1]
        # 标准差过小
        if stdT < thrSTD[0] * meanT:
            k3, k2, k1 = [3.5, 3, 2.5]
        if stdT < thrSTD[1] * meanT:
            k3, k2, k1 = [5, 3.6, 2.8]

        for i in range(n[0], num - n[1]):
            if uncov[i] == 1:
                if difT[i] > k3 * stdT:
                    diag[i] = levelSC[3]
                    if avgT[i] < thAVG[2]:
                        diag[i] = 2
                elif difT[i] > k2 * stdT:
                    diag[i] = levelSC[2]
                    if meanT < thAVG[1] and avgT[i] > thAVG[2]:
                        diag[i] = 2
                elif difT[i] > k1 * stdT:
                    diag[i] = levelSC[1]
                elif meanT < thAVG[1] and avgT[i] > thAVG[2]:
                    diag[i] = levelSC[1]

                if avgT[i] < thAVG[0]:
                    diag[i] = levelSC[0]

        # 对最前、后n块板极中未被多层盖布遮挡的板极单独做阈值检测
        #thT = [120, 140, 160]
        #th = self.T2P(thT, minT, maxT)
        '''
        th0 = [180,190,200]
        th = self.thDynamic(th0, minT, maxT)
        # th = [135,145,160] # 两端板极检测阈值
        for i in range(-n[1], n[0]):
            if uncov[i] == 1:
                if avgT[i] > th[2]:
                    diag[i] = levelSC[3]
                elif avgT[i] > th[1]:
                    diag[i] = levelSC[2]
                elif avgT[i] > th[0]:
                    diag[i] = levelSC[1]
        '''
        return diag

    def DistorRemove(self, im, k1, k2):
        # 桶形畸变矫正
        s = im.shape
        img = np.zeros(s)
        img = np.uint8(img)

        for l1 in range(s[0]):
            y = l1 - s[0] / 2

            for l2 in range(s[1]):
                x = l2 - s[1] / 2
                x1 = np.round(x * (1 + k1 * x * x + k2 * y * y))
                y1 = np.round(y * (1 + k1 * x * x + k2 * y * y))
                x1 = np.int(x1 + s[1] / 2)
                y1 = np.int(y1 + s[0] / 2)

                # 超出边界部分强制为0
                if x1 < 0 and x1 >= s[1] and y1 < 0 and y1 >= s[0]:
                    img[l1, l2] = 0;
                else:
                    img[l1, l2] = im[y1, x1]
        return img

    def CropOfBars(im):
        # 单槽自动裁剪（待完善）
        pass

    def DecInit(self):
        # 生成key为‘槽号-板极号’，值为0的初始化字典
        diag = {}
        for i in range(self.num1[0], self.num1[1] + 1):
            for j in range(self.num2[0], self.num2[1] + 1):
                key = str(i) + '-' + str(j)
                diag[key] = [0 for i in range(self.num3)];
        return diag

    def stdDetect2(self,n1,n2):
        # 所有头、尾板另行检测
        levelSC = self.levelSC
        Ln = self.ListExtr_ns
        Lavg = []
        Lavg2 = []
        Ln2 = []

        k = n1*n2

        # 忽略边缘
        for i in range(k):
            j = Ln[i][0]
            if j > 0:
                Ln[i][0] = Ln[i][0]-1

            j = Ln[i][1]
            if j > 0:
                Ln[i][1] = Ln[i][1]-1


        for i in range(k):
            if Ln[i] == [0,0]:
                Lavg.append([])
            elif Ln[i][1] == 0:
                Lavg.append(self.ListExtr_avg[i][0:Ln[i][0]])
            elif Ln[i][0] == 0:
                Lavg.append(self.ListExtr_avg[i][-Ln[i][1]::])
            else:
                Lavg.append(self.ListExtr_avg[i][0:Ln[i][0]]+self.ListExtr_avg[i][-Ln[i][1]::])

            Lavg2 = Lavg2 + Lavg[i]

        mExtr = np.mean(Lavg2)
        sExtr = np.std(Lavg2)

        print('mExtr:',mExtr)
        print('sExtr:',sExtr)
        print('Lavg2:',Lavg2)

        warncof = [0.5, 1, 2]
        #warnadd = [10,20,30]

        warnLine = [mExtr + i*sExtr for i in warncof]
        #warnLine = [mExtr + i  for i in warnadd]

        diag = [[0 for i in range(self.num3)] for j in range(k)]

        for i in range(k):
            n = Ln[i]
            for j in range(-n[1],n[0]):
                x = Lavg[i][j]
                if x > warnLine[2]:
                    diag[i][j] = levelSC[3]
                elif x > warnLine[1]:
                    diag[i][j] = levelSC[2]
                elif x > warnLine[0]:
                    diag[i][j] = levelSC[1]

        return diag

    def ShortCircuitDetect(self, im, minT=30, maxT=90, num3=38, num2=[1, 12], num1=[1, 2]):
        # 短路检测主程序
        im = im.convert('L')  # 转灰度图
        im = np.array(im)  # 图片转数组形式存储

        # 生成初始化字典,全0
        diag = self.DecInit()
        diag1 = []
        diag2 = []
        diag3 = []

        # 桶形畸变矫正
        k1 = -3e-7;
        k2 = -4e-7;
        img = self.DistorRemove(im, k1, k2)
        plt.imshow(img, cmap='gray', interpolation='bicubic')
        plt.show()

        # 手动定位裁剪
        p = [513, 942, 4, 465]  # 整槽1、2的上下纵坐标位置
        # q = [[[21,14,95,370],[116,19,194,380],[214,20,300,389],[321,27,413,398],[429,27,519,409],[548,24,637,406],[668,34,755,418],[779,35,864,411],[899,30,967,405],[1010,32,1069,412],[1106,35,1170,406],[1205,32,1264,400]],[[13,32,114,416],[117,35,205,415],[223,26,310,416],[331,25,422,418],[447,24,543,419],[559,25,657,424],[679,26,777,425],[796,29,884,426],[905,36,1000,433],[1014,42,1099,436],[1120,53,1199,439],[1229,56,1277,444]],]
        q = [[[10, 13, 101, 370], [116, 16, 192, 377], [216, 18, 295, 388], [321, 22, 414, 395], [430, 24, 522, 404],
              [550, 27, 641, 408], [664, 30, 754, 411], [784, 32, 853, 410], [902, 34, 970, 413], [1010, 35, 1070, 405],
              [1109, 43, 1172, 402], [1202, 37, 1267, 402]],
             [[3, 33, 113, 418], [119, 28, 213, 416], [226, 29, 311, 416], [332, 26, 423, 418], [447, 24, 542, 419],
              [561, 26, 661, 422], [676, 27, 775, 425], [802, 34, 886, 428], [908, 39, 998, 431], [1017, 47, 1098, 435],
              [1123, 56, 1197, 440], [1229, 56, 1279, 444]]]
        # 所有单槽中的板极短路检测
        n1 = num1[1] - num1[0] + 1
        n2 = num2[1] - num2[0] + 1
        for i in range(n1):
            # 上、下整槽分离
            imBars = img[(p[2 * i] - 1):p[2 * i + 1], 0:]
            # 单槽分离及其板极短路检测
            for j in range(n2):
                im1bar = imBars[(q[i][j][1] - 1):q[i][j][3], (q[i][j][0] - 1):q[i][j][2]]
                im1bar = np.resize(im1bar,[num3*10,100])
                # plt.imshow(im1bar,cmap='gray',interpolation='bicubic')
                # plt.show()
                diag1.append(self.stdDetect(im1bar.T, minT, maxT))  # 输入图片中板极纵向排列，0:正常 1:轻度 2:中度 3:重度

        diag2 = self.stdDetect2(n1,n2)

        print('diag1:',diag1)
        print('diag2:',diag2)

        for i in range(n1):
            for j in range(n2):
                k = i*n2 + j
                diag3 = [diag1[k][k1]+diag2[k][k1] for k1 in range(self.num3)]
                key = str(i + 1) + '-' + str(j + 1)
                diag[key] = diag3

                #
                # plt.figure()
                # plt.subplot(2, 1, 1)
                # plt.imshow(im1bar.T, cmap='gray', interpolation='bicubic')
                # plt.subplot(2, 1, 2)
                # plt.axis([1, num3, 0, 3])
                # plt.plot(list(range(1, num3 + 1)), diagBars, marker='*')
                # plt.savefig('SDC_' + str(i + 1) + '-' + str(j + 1) + '.jpg', dpi=120)
                # plt.show()

        return diag

    def MyCheck(self, path, maxT = 90, minT = 30):
        '''
        filePath = 'E:\\MatlabCode\\ElecBarCrop_20210707\\JiangXi\\Images\\'
        imList = os.listdir(filePath)
    #    print(imList)
        k=0
        #l=len(imList)
        #imPath = 'E:\\MatlabCode\\ElecBarCrop_20210707\\JiangXi\\ImTest.jpg'
        imPath = filePath+imList[k]
        '''

        # 'E:\\PythonProject\\SCD\\Images\\capture20210716_082701.jpg'
        imPath = path  # 'E:\\PythonProject\\ShortCircuitDetection\\Test003.jpg'
        num1 = [1, 2]  # 起始-结束整槽号
        num2 = [1, 12]  # 起始-结束单槽号
        num3 = 38  # number of plates in one electrobath
        # print(imPath)
        img = Image.open(imPath)  # read the image ( PIL image )
        diag = self.ShortCircuitDetect(img, minT, maxT, num3, num2, num1)  # 短路检测
        return diag

    def __init__(self):

        self.num1 = [1, 2]  # 起始-结束整槽号
        self.num2 = [1, 12]  # 起始-结束单槽号
        self.num3 = 38  # number of plates in one electrobath
        self.levelSC = [0, 1, 2, 3] # 0:正常, 1:疑似, 2:一般, 3:严重

        self.ListExtr_ns = []
        self.ListExtr_avg = []

